package com.penglecode.nio.socket;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class EchoServer implements Runnable {

	private static final Log logger = LogFactory.getLog(EchoServer.class);
	
	/**
	 * 默认ServerSocket绑定的端口号
	 */
	public static final int DEFAULT_SERVER_PORT = 9999;
	
	/**
	 * 服务器Channel绑定的端口号
	 */
	private int port;
	
	/**
	 * 服务器Channel对象，负责接受用户连接
	 */
	private ServerSocketChannel server;
	
	/**
	 * Selector对象，负责监控所有的连接到服务器的网络事件的发生
	 */
	private Selector selector;
	
	private ConnectionHandler serverHandler;
	
	public EchoServer() {
		super();
		try {
			this.port = DEFAULT_SERVER_PORT; //初始化服务器Channel绑定的端口号为DEFAULT_SERVER_PORT
			this.selector = Selector.open(); //初始化Selector对象
			this.server = ServerSocketChannel.open(); //初始化服务器Channel对象
			this.server.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), this.port)); //socket与端口绑定
			this.server.configureBlocking(false); //将服务器Channel设置为非阻塞模式
			this.server.register(selector, SelectionKey.OP_ACCEPT); //将服务器Channel注册到Selector对象，并指出服务器Channel所感兴趣的事件为可接受请求操作
			this.serverHandler = new ServerHandler(this.selector);
		} catch (IOException e) {
			logger.error(e, e);
		}
	}

	public void run() {
		while(true){
			try {
				/**
				 * 应用Select机制轮循是否有用户感兴趣的新的网络事件发生，当没有
				 * 新的网络事件发生时，此方法会阻塞，直到有新的网络事件发生为止
				 */
				int flag = selector.select();
				System.out.println(">>> server heartbeat! flag = " + flag);
				/**
				 * 程序走到这里，说明有新的网络事件发生了
				 * 接着，得到活动的网络连接选择键的集合
				 */
				Set<SelectionKey> selectionKeys = selector.selectedKeys();
				if(selectionKeys.size() == 0){
					continue; //继续进行while循环操作
				}
				Iterator<SelectionKey> iterator = selectionKeys.iterator();
				while(iterator.hasNext()){
					SelectionKey selectionKey = iterator.next();
					iterator.remove();
					if(selectionKey.isAcceptable()){ //如果此Key的通道状态是为可接受，则接受连接，注册通道，以接受更多的事件，进行相关的服务器程序处理
						this.serverHandler.handleConnect(selectionKey);
						continue;
					}
					if(selectionKey.isReadable()){ //如果此Key的通道状态为可读，则说明Channel是一个客户端的连接通道，进行相应的读取客户端数据的操作
						this.serverHandler.handleRead(selectionKey);
						continue;
					}
					if(selectionKey.isWritable()){ //如果此Key的通道状态为可写，则也说明Channel是一个客户端的连接通道，进行相应的向客户端写数据的操作
						this.serverHandler.handleWrite(selectionKey);
						continue;
					}
				}
			} catch (Exception e) {
				logger.error(e, e);
				continue; //当有异常发生时，继续进行while循环操作
			}
		}
	}
	
	public static void main(String[] args) {
		new Thread(new EchoServer()).start();
	}

}
